From 1f8c7a25249373b54884968211c7c6d24331dc86 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Tue, 13 Aug 2013 14:13:04 +0200 Subject: [PATCH] Better parsing for global ostree options * Specifying global options after the command for a more natural: # ostree commit --repo=/path/to/repo ... * Support asking for --help without --repo # ostree commit --help * Support short form of -h * Support specifying --repo without equals sign # ostree --repo /path/to/repo commit ... * Support global --help and -h # ostree --help * Ditto for ostree admin sub commands * Removed some leaky code https://bugzilla.gnome.org/show_bug.cgi?id=705903 --- src/ostree/ot-builtin-admin.c | 102 ++++++++++++++++++++---- src/ostree/ot-main.c | 143 +++++++++++++++++++++++----------- src/ostree/ot-main.h | 7 -- 3 files changed, 185 insertions(+), 67 deletions(-) diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c index e6aaee68..16d633e4 100644 --- a/src/ostree/ot-builtin-admin.c +++ b/src/ostree/ot-builtin-admin.c @@ -54,19 +54,95 @@ ostree_builtin_admin (int argc, char **argv, GFile *repo_path, GCancellable *can { gboolean ret = FALSE; const char *opt_sysroot = "/"; - const char *subcommand_name; + const char *subcommand_name = NULL; OstreeAdminCommand *subcommand; - int subcmd_argc; gs_unref_object GFile *sysroot = NULL; - char **subcmd_argv = NULL; + gboolean want_help = FALSE; + int in, out, i; + gboolean skip; - if (argc > 1 && g_str_has_prefix (argv[1], "--sysroot=")) + /* + * Parse the global options. We rearrange the options as + * necessary, in order to pass relevant options through + * to the commands, but also have them take effect globally. + */ + + for (in = 1, out = 1; in < argc; in++, out++) { - opt_sysroot = argv[1] + strlen ("--sysroot="); - argc--; - argv++; + /* The non-option is the command, take it out of the arguments */ + if (argv[in][0] != '-') + { + skip = (subcommand_name == NULL); + if (subcommand_name == NULL) + subcommand_name = argv[in]; + } + + /* The global long options */ + else if (argv[in][1] == '-') + { + skip = FALSE; + + if (g_str_equal (argv[in], "--")) + { + break; + } + else if (g_str_equal (argv[in], "--help")) + { + want_help = TRUE; + } + else if (g_str_equal (argv[in], "--sysroot") && in + 1 < argc) + { + opt_sysroot = argv[in + 1]; + skip = TRUE; + in++; + } + else if (g_str_has_prefix (argv[in], "--sysroot=")) + { + opt_sysroot = argv[in] + 10; + skip = TRUE; + } + else if (subcommand_name == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown or invalid admin option: %s", argv[in]); + goto out; + } + } + + /* The global short options */ + else + { + skip = FALSE; + for (i = 1; argv[in][i] != '\0'; i++) + { + switch (argv[in][i]) + { + case 'h': + want_help = TRUE; + break; + + default: + if (subcommand_name == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown or invalid admin option: %s", argv[in]); + goto out; + } + break; + } + } + } + + /* Skipping this argument? */ + if (skip) + out--; + else + argv[out] = argv[in]; } - else if (argc <= 1 || g_str_has_prefix (argv[1], "--help")) + + argc = out; + + if (subcommand_name == NULL || want_help) { subcommand = admin_subcommands; g_print ("usage: ostree admin --sysroot=PATH COMMAND [options]\n"); @@ -76,11 +152,9 @@ ostree_builtin_admin (int argc, char **argv, GFile *repo_path, GCancellable *can g_print (" %s\n", subcommand->name); subcommand++; } - return argc <= 1 ? 1 : 0; + return subcommand_name == NULL ? 1 : 0; } - subcommand_name = argv[1]; - subcommand = admin_subcommands; while (subcommand->name) { @@ -92,14 +166,12 @@ ostree_builtin_admin (int argc, char **argv, GFile *repo_path, GCancellable *can if (!subcommand->name) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "Unknown command '%s'", subcommand_name); + "Unknown admin command '%s'", subcommand_name); goto out; } - ostree_prep_builtin_argv (subcommand_name, argc-2, argv+2, &subcmd_argc, &subcmd_argv); - sysroot = g_file_new_for_path (opt_sysroot); - if (!subcommand->fn (subcmd_argc, subcmd_argv, sysroot, cancellable, error)) + if (!subcommand->fn (argc, argv, sysroot, cancellable, error)) goto out; ret = TRUE; diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index 243dfda1..4691bce2 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -55,26 +55,6 @@ ostree_usage (char **argv, return (is_error ? 1 : 0); } -void -ostree_prep_builtin_argv (const char *builtin, - int argc, - char **argv, - int *out_argc, - char ***out_argv) -{ - int i; - char **cmd_argv; - - cmd_argv = g_new0 (char *, argc + 2); - - cmd_argv[0] = (char*)builtin; - for (i = 0; i < argc; i++) - cmd_argv[i+1] = argv[i]; - cmd_argv[i+1] = NULL; - *out_argc = argc+1; - *out_argv = cmd_argv; -} - int ostree_run (int argc, char **argv, @@ -84,14 +64,13 @@ ostree_run (int argc, OstreeCommand *command; GError *error = NULL; GCancellable *cancellable = NULL; - int cmd_argc; - char **cmd_argv = NULL; - gboolean have_repo_arg; const char *cmd = NULL; const char *repo = NULL; const char *host_repo_path = "/ostree/repo"; GFile *repo_file = NULL; - int arg_off; + gboolean want_help = FALSE; + gboolean skip; + int in, out, i; /* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */ g_setenv ("GIO_USE_VFS", "local", TRUE); @@ -103,23 +82,101 @@ ostree_run (int argc, if (argc < 2) return ostree_usage (argv, commands, TRUE); - if (g_str_has_prefix (argv[1], "--version")) + /* + * Parse the global options. We rearrange the options as + * necessary, in order to pass relevant options through + * to the commands, but also have them take effect globally. + */ + + for (in = 1, out = 1; in < argc; in++, out++) { - g_print ("%s\n %s\n", PACKAGE_STRING, OSTREE_FEATURES); - return 0; - } + /* The non-option is the command, take it out of the arguments */ + if (argv[in][0] != '-') + { + skip = (cmd == NULL); + if (cmd == NULL) + cmd = argv[in]; + } - have_repo_arg = g_str_has_prefix (argv[1], "--repo="); + /* The global long options */ + else if (argv[in][1] == '-') + { + skip = FALSE; + + if (g_str_equal (argv[in], "--")) + { + break; + } + else if (g_str_equal (argv[in], "--help")) + { + want_help = TRUE; + } + else if (g_str_equal (argv[in], "--repo") && in + 1 < argc) + { + repo = argv[in + 1]; + skip = TRUE; + in++; + } + else if (g_str_has_prefix (argv[in], "--repo=")) + { + repo = argv[in] + 7; + skip = TRUE; + } + else if (cmd == NULL && g_str_equal (argv[in], "--version")) + { + g_print ("%s\n %s\n", PACKAGE_STRING, OSTREE_FEATURES); + return 0; + } + else if (cmd == NULL) + { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown or invalid global option: %s", argv[in]); + goto out; + } + } - if (!have_repo_arg) - { - arg_off = 2; - cmd = argv[arg_off-1]; + /* The global short options */ + else + { + skip = FALSE; + for (i = 1; argv[in][i] != '\0'; i++) + { + switch (argv[in][i]) + { + case 'h': + want_help = TRUE; + break; + + default: + if (cmd == NULL) + { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown or invalid global option: %s", argv[in]); + goto out; + } + break; + } + } + } + + /* Skipping this argument? */ + if (skip) + out--; + else + argv[out] = argv[in]; } - else + + argc = out; + + if (cmd == NULL) { - arg_off = 3; - cmd = argv[arg_off-1]; + if (!want_help) + { + g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No command specified"); + } + ostree_usage (argv, commands, TRUE); + goto out; } command = commands; @@ -139,12 +196,11 @@ ostree_run (int argc, g_set_prgname (g_strdup_printf ("ostree %s", cmd)); - if (!(command->flags & OSTREE_BUILTIN_FLAG_NO_REPO)) + if (repo == NULL && !want_help && + !(command->flags & OSTREE_BUILTIN_FLAG_NO_REPO)) { - if (have_repo_arg) - repo = argv[1] + strlen ("--repo="); - else if (g_file_test ("objects", G_FILE_TEST_IS_DIR) - && g_file_test ("config", G_FILE_TEST_IS_REGULAR)) + if (g_file_test ("objects", G_FILE_TEST_IS_DIR) + && g_file_test ("config", G_FILE_TEST_IS_REGULAR)) repo = "."; else if (g_file_test (host_repo_path, G_FILE_TEST_EXISTS)) repo = host_repo_path; @@ -160,13 +216,10 @@ ostree_run (int argc, if (repo) repo_file = g_file_new_for_path (repo); - ostree_prep_builtin_argv (cmd, argc-arg_off, argv+arg_off, &cmd_argc, &cmd_argv); - - if (!command->fn (cmd_argc, cmd_argv, repo_file, cancellable, &error)) + if (!command->fn (argc, argv, repo_file, cancellable, &error)) goto out; out: - g_free (cmd_argv); g_clear_object (&repo_file); if (error) { diff --git a/src/ostree/ot-main.h b/src/ostree/ot-main.h index b314f8ff..41adee40 100644 --- a/src/ostree/ot-main.h +++ b/src/ostree/ot-main.h @@ -35,13 +35,6 @@ typedef struct { int flags; /* OstreeBuiltinFlags */ } OstreeCommand; -void -ostree_prep_builtin_argv (const char *builtin, - int argc, - char **argv, - int *out_argc, - char ***out_argv); - int ostree_main (int argc, char **argv, OstreeCommand *commands); int ostree_run (int argc, char **argv, OstreeCommand *commands, GError **error); -- 2.30.2